﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Reflection;
using ylyfDataCommon.Exceptions;
using ylyfDataEntityConverter.Common;
using ylyfDataEntityConverter.GenerticEntityConverter;

namespace ylyfDataEntityConverter.GenerticEntityConverterV2
{
    public class DataEntityConverter<T> : EntityConverter<T> where T : new()
    {
        private EntityType currentEntityType { get; }

        private TypeData fatherInstanceTypeData { get; set; }

        private Dictionary<string, List<InsteadInfo>> TranslatePlanDic = new Dictionary<string, List<InsteadInfo>>();


        public DataEntityConverter()
        {
            Type Ttype = typeof(T);

            if (typeof(IDictionary).IsAssignableFrom(Ttype))
            {
                if (Ttype == typeof(Dictionary<string, object>))
                {
                    currentEntityType = EntityType.ObjectDictionary;
                    return;
                }
                if (Ttype == typeof(Dictionary<string, string>))
                {
                    currentEntityType = EntityType.StringDictionary;
                    return;
                }
                throw new ClassNotSuportedInThisConverterException();
            }
            if (Ttype.IsPrimitive || Ttype == typeof(string) || Ttype.IsEnum || Ttype == typeof(Guid) || Ttype == typeof(DateTime))
            {
                currentEntityType = EntityType.Primitive;
                return;
            }
            fatherInstanceTypeData = GenerateTypeData(Ttype);

        }

        private TypeData GenerateTypeData(Type type, string lastPropertyStr = "")
        {
            Guid id = Guid.NewGuid();
            TypeData typeData = new TypeData(id)
            {
                thisType = type,
                sonTypes = new Dictionary<PropertyInfo, TypeData>()
            };
            var properties = type.GetProperties();
            foreach (PropertyInfo property in properties)
            {
                var Ttype = property.PropertyType;
                string propName = property.Name;
                if (property.GetCustomAttributes(typeof(EntityConverterIgnoreAttribute), false).Length > 0)
                    continue;
                if (property.GetCustomAttributes(typeof(DataColumnNameAttribute), false).Length > 0)
                {
                    var tmpname = ((DataColumnNameAttribute)
                        property.GetCustomAttributes(typeof(DataColumnNameAttribute), false)[0]).ColumnName;
                    if (!string.IsNullOrWhiteSpace(tmpname))
                        propName = tmpname;
                }
                if (Ttype.IsPrimitive || Ttype == typeof(string) || Ttype.IsEnum || Ttype == typeof(Guid) || Ttype == typeof(DateTime))
                {
                    if (!TranslatePlanDic.ContainsKey(propName.ToLower()) || TranslatePlanDic[propName.ToLower()] == null)
                    {
                        TranslatePlanDic[propName.ToLower()] = new List<InsteadInfo>();
                    }
                    TranslatePlanDic[propName.ToLower()].Add(new InsteadInfo()
                    {
                        instancePropertyInfo = property,
                        InstanceId = id
                    });
                    string moreStr = lastPropertyStr + propName.ToLower();
                    if (!TranslatePlanDic.ContainsKey(moreStr) || TranslatePlanDic[moreStr] == null)
                    {
                        TranslatePlanDic[moreStr] = new List<InsteadInfo>();
                    }
                    TranslatePlanDic[moreStr].Add(new InsteadInfo()
                    {
                        instancePropertyInfo = property,
                        InstanceId = id
                    });
                }
                else
                {
                    if (Ttype.GetGenericArguments().Length > 0)
                    {
                        continue;
                    }
                    typeData.sonTypes[property] =
                        GenerateTypeData(Ttype, lastPropertyStr + propName.ToLower() + ".");
                }
            }
            return typeData;

        }
        public List<T> RetriveEntity(DataTable resultTable)
        {
            if (resultTable.Rows.Count <= 0)
                return null;
            //分流处理方式
            switch (currentEntityType)
            {
                case EntityType.Standard:
                    {
                        return RetriveEntity(resultTable, InitColumn(resultTable));
                    }
                case EntityType.ObjectDictionary:
                    {
                        return RetriveDictionary(resultTable, InitColumn(resultTable));
                    }
                case EntityType.StringDictionary:
                    {
                        return RetriveStringDictionary(resultTable, InitColumn(resultTable));
                    }
                case EntityType.Primitive:
                    {
                        return RetrivePrimitive(resultTable);
                    }
            }
            return null;
        }


        #region 初始化实例




        private Tuple<T, Dictionary<Guid, object>> InitInstance()
        {
            Dictionary<Guid, object> objectList = new Dictionary<Guid, object>();
            var result = initSonInstance(fatherInstanceTypeData, ref objectList);
            return Tuple.Create((T)result.Item1, result.Item2);
        }

        private Tuple<object, Dictionary<Guid, Object>> initSonInstance(TypeData typeData, ref Dictionary<Guid, Object> dic)
        {
            if (typeData.thisType == null)
            {
                return null;
            }
            object instance = Activator.CreateInstance(typeData.thisType);
            if (typeData.sonTypes != null)
            {
                foreach (KeyValuePair<PropertyInfo, TypeData> typeDataSonType in typeData.sonTypes)
                {
                    typeDataSonType.Key.SetValue(instance, initSonInstance(typeDataSonType.Value, ref dic).Item1, null);
                }

            }
            return Tuple.Create(instance, dic);

        }
        #endregion


        #region 类型处理机制

        public List<T> RetriveEntity(DataTable table, List<DataColumn> colList)
        {
            List<T> tlist = new List<T>();


            foreach (DataRow row in table.Rows)
            {
                var data = InitInstance();
                var TranslateClone = new Dictionary<string, List<InsteadInfo>>();
                foreach (var v in TranslatePlanDic)
                {
                    TranslateClone[v.Key] = new List<InsteadInfo>();
                    foreach (InsteadInfo insteadInfo in v.Value)
                    {
                        TranslateClone[v.Key].Add(insteadInfo.clone(data.Item2[insteadInfo.InstanceId]));
                    }
                }
                foreach (DataColumn col in colList)
                {
                    string str = col.ColumnName;
                    List<InsteadInfo> prop = null;
                    if (TranslateClone.ContainsKey(str.ToLower()))
                        prop = TranslateClone[str.ToLower()];
                    if (prop == null && TranslateClone.ContainsKey(str))
                        prop = TranslateClone[str];
                    foreach (InsteadInfo info in prop)
                    {
                        if (info.instance == null || info.instancePropertyInfo == null || !info.instancePropertyInfo.CanWrite)
                        {
                            continue;
                        }
                        try
                        {
                            info.instancePropertyInfo.SetValue(info.instance,
                                TypeDescriptor.GetConverter(info.instancePropertyInfo.PropertyType)
                                    .ConvertFrom(row[str].ToString()), null);
                        }
                        catch (Exception)
                        {

                        }
                    }
                }
                tlist.Add(data.Item1);
            }

            return tlist;
        }


        /// <summary>
        ///     生成Object字典
        /// </summary>
        /// <param name="table">数据表</param>
        /// <param name="colList">列数据</param>
        /// <returns></returns>
        private List<T> RetriveDictionary(DataTable table, List<DataColumn> colList)
        {
            List<T> t = new List<T>();

            foreach (DataRow row in table.Rows)
            {
                T tobj = new T();
                object obj = tobj;
                Dictionary<string, object> dic = (Dictionary<string, object>)obj;
                foreach (DataColumn column in colList)
                    try
                    {
                        dic.Add(column.ColumnName,
                            TypeDescriptor.GetConverter(column.DataType).ConvertFrom(row[column].ToString()));
                    }
                    catch
                    {
                    }
                t.Add(tobj);
            }
            return t;
        }

        /// <summary>
        ///     生成String字典
        /// </summary>
        /// <param name="table">数据表</param>
        /// <param name="colList">列数据</param>
        /// <returns></returns>
        private List<T> RetriveStringDictionary(DataTable table, List<DataColumn> colList)
        {
            List<T> t = new List<T>();

            foreach (DataRow row in table.Rows)
            {
                T tobj = new T();
                Object obj = tobj;
                Dictionary<string, string> dic = (Dictionary<string, string>)obj;
                foreach (DataColumn column in colList)
                    try
                    {
                        dic.Add(column.ColumnName, row[column].ToString());
                    }
                    catch
                    {
                    }
                t.Add(tobj);
            }
            return t;
        }

        /// <summary>
        ///     单对象获取机制
        /// </summary>
        /// <param name="table">数据表</param>
        /// <returns></returns>
        private List<T> RetrivePrimitive(DataTable table)
        {
            List<T> entity = new List<T>();
            foreach (DataRow row in table.Rows)
                try
                {
                    entity.Add((T)TypeDescriptor.GetConverter(typeof(T)).ConvertFrom(row[0].ToString()));
                }
                catch (Exception)
                {
                }
            return entity;
        }

        #endregion

        private List<DataColumn> InitColumn(DataTable resultTable)
        {
            //处理DataTable的列和列类型读入缓存
            List<DataColumn> colList = new List<DataColumn>();
            foreach (DataColumn column in resultTable.Columns) //将列名读入缓存
                try
                {
                    colList.Add(column);
                }
                catch
                {
                }
            return colList;
        }
    }


    #region 路由方案

    enum EntityType
    {
        Standard = 0, ObjectDictionary = 1, Primitive = 2, StringDictionary = 3
    }

    #endregion


    class InsteadInfo
    {
        public InsteadInfo clone(object obj)
        {
            return new InsteadInfo()
            {
                instance = obj,
                InstanceId = this.InstanceId,
                instancePropertyInfo = this.instancePropertyInfo
            };
        }
        public object instance { get; set; }
        public PropertyInfo instancePropertyInfo { get; set; }
        public Guid InstanceId { get; set; }
    }

    class TypeData
    {
        public TypeData(Guid tid)
        {
            typeId = tid;
        }
        public Guid typeId { get; private set; }
        public Type thisType { get; set; }
        public Dictionary<PropertyInfo, TypeData> sonTypes { get; set; }
    }

}